package com.softserveinc.network;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.json.JSONException;
import org.xml.sax.SAXException;

import android.content.Context;
import android.util.Log;

import com.softserveinc.MovieManagerApplication;
import com.softserveinc.model.Movie;
import com.softserveinc.model.MovieDetails;
import com.softserveinc.parser.Parser;
import com.softserveinc.parser.ParserFactory;
import com.softserveinc.settings.HardwareManager;
import com.softserveinc.settings.SettingsManager;
import com.softserveinc.util.NoConnectionException;

public class ApiClient {

	private static final String TAG = ApiClient.class.getSimpleName();

	private static final String MOVIE_SEARCH = "Movie.search";
	private static final String MOVIE_BROWSE = "Movie.browse";
	private static final String MOVIE_GET_INFO = "Movie.getInfo";

	private static final String API = "http://api.themoviedb.org/2.1/";
	private static final String APIKEY = "480accefd554f1ec0c87f1da5c90caf8";

	private static final String ORDER_BY = "?order_by=";
	private static final String SLASH = "/";
	private static final String URL_UTIL = "&order=desc&countries=us";
	private static final String RATING_RESTRICTION = "min_votes=10&rating_min=5.0&rating_max=9.0&";
	private static final String RELEASE_DATE_RESTRICTION = "&release_min=1287476227"
			+ "&release_max=1319012227&";
	private static final String PER_PAGE = "&per_page=";
	private static final String PAGE = "page=";

	private static final int FIRST_PAGE = 1;

	private static final int RETRY_TIMES = 5;

	private static final int CONNECTION_TIME_OUT = 300000;

	private final HardwareManager hardwareManager;
	private final SettingsManager settingsManager;

	public ApiClient(final Context context) {
		MovieManagerApplication application = (MovieManagerApplication) context
				.getApplicationContext();

		hardwareManager = application.getHardwareManager();
		settingsManager = application.getSettingsManager();
	}

	public List<Movie> getMovieList(final String order, final String size,
			final int page) throws JSONException, ParseException {

		String language = Locale.getDefault().getLanguage();

		String feedbackType = settingsManager.getFeedbackType();
		String address = API + MOVIE_BROWSE + SLASH + language + SLASH
				+ feedbackType + SLASH + APIKEY + ORDER_BY + order + URL_UTIL
				+ RELEASE_DATE_RESTRICTION + RATING_RESTRICTION + PAGE + page
				+ PER_PAGE + size;

		return getMovieListForAddress(address, feedbackType);
	}

	public List<Movie> getMovieList(final String order, final String size)
			throws JSONException, ParseException {

		int page = FIRST_PAGE;

		return getMovieList(order, size, page);
	}

	public List<Movie> getMovieList(final String query) throws JSONException,
			ParseException {
		String language = Locale.getDefault().getLanguage();

		String feedbackType = settingsManager.getFeedbackType();

		String address = API + MOVIE_SEARCH + SLASH + language + SLASH
				+ feedbackType + SLASH + APIKEY + SLASH + query;

		return getMovieListForAddress(address, feedbackType);
	}

	private List<Movie> getMovieListForAddress(final String address,
			final String feedbackType) throws JSONException, ParseException {
		Log.d(TAG, address);

		if (hardwareManager.isNetworkConnected()) {
			InputStream responseStream = getResponseStream(address);
			List<Movie> movies = new ArrayList<Movie>();
			Parser parser = ParserFactory.createParser(feedbackType);
			try {
				movies.addAll(parser.parseMovieList(responseStream));
			} catch (SAXException e) {
				Log.e(TAG, e.getMessage(), e);
			}

			Log.d(TAG, "movie list size returned from API " + movies.size());
			return movies;
		} else {
			throw new NoConnectionException();
		}
	}

	public MovieDetails getMovieDetails(final int movieID)
			throws JSONException, ParseException {
		if (hardwareManager.isNetworkConnected()) {
			String feedbackType = settingsManager.getFeedbackType();
			String language = Locale.getDefault().getLanguage();

			String address = API + MOVIE_GET_INFO + SLASH + language + SLASH
					+ feedbackType + SLASH + APIKEY + SLASH + movieID;

			InputStream responseStream = getResponseStream(address);

			MovieDetails movieDetails = new MovieDetails();

			Parser parser = ParserFactory.createParser(feedbackType);

			try {
				movieDetails = parser.parseMovieDetails(responseStream);
			} catch (SAXException e) {
				Log.e(TAG, e.getMessage(), e);
			}

			return movieDetails;
		} else {
			throw new NoConnectionException();
		}
	}

	private InputStream getResponseStream(final String address) {
		int retry = 0;

		for (;;) {
			try {
				URL url = new URL(address);

				URLConnection urlConnection = url.openConnection();
				urlConnection.setConnectTimeout(CONNECTION_TIME_OUT);
				urlConnection.connect();

				InputStream responseStream = urlConnection.getInputStream();
				return responseStream;
			} catch (Exception e) {
				Log.w(TAG, "warning: " + e.getMessage());
				if (retry == RETRY_TIMES) {
					Log.e(TAG, "error: " + e.getMessage(), e);
					break;
				}
			}
		}

		return null;
	}
}
